import { assetManager, IQuatLike, IVec3Like, math } from "cc";
import { Debug } from "./Debug";

export default class MathUtils {

    constructor() {
    }

    /**
     * 弧度制转换为角度值
     * @param {number} radian
     * @returns {number}
     */
    public static getAngle(radian: number) {
        return 180 * radian / Math.PI;
    }

    /**
     * 角度值转换为弧度制
     * @param {number} angle
     */
    public static getRadian(angle: number) {
        return angle / 180 * Math.PI;
    }


    /**
   * 2点之间的夹角弧度
   * @param {*} pointA 
   * @param {*} pointB 
   */
    public static getRadianByPoint(pointA: any, pointB: any) {
        //atan((B.y-A.y)/(A.x-B.x)) 
        return Math.atan2((pointB.y - pointA.y), (pointB.x - pointA.x))
    }
    /**
     * 2点之间的夹角
     * @param {*} pointA 
     * @param {*} pointB 
     */
    public static getAngleByPoint(pointA: any, pointB: any) {
        return this.getRadianByPoint(pointA, pointB) * 180 / Math.PI
    }


    /**
     * 根据角度旋转向量
     * @param vec 
     * @param angle 
     */
    public static vecRotate(vec: any, angle: any) {
        let radians = MathUtils.getRadian(angle);
        let sin = Math.sin(radians);
        let cos = Math.cos(radians);
        let x1 = cos * vec.x - sin * vec.y;
        let y1 = sin * vec.x + cos * vec.y;
        return new math.Vec2(x1, y1);
    }

    /**
     * 获取两点间弧度
     * @param {Point} p1
     * @param {Point} p2
     * @returns {number}
     */
    public static getRadianTwoPoint(p1: any, p2: any) {
        let xdis = p2.x - p1.x;
        let ydis = p2.y - p1.y;
        return Math.atan2(ydis, xdis);
    }

    /**
     * 获取两点间旋转角度（顺时针）
     * @param {Point} p1
     * @param {Point} p2
     * @returns {number}
     */
    public static getAngleTwoPoint(p1: any, p2: any) {
        let vy = p2.y - p1.y;
        let vx = p2.x - p1.x;
        let ang;

        if (vy == 0) {
            if (vx < 0) {
                return 180;
            }
            return 0;
        }

        if (vx == 0) { //正切是vy/vx所以vx==0排除
            if (vy > 0) {
                ang = 90;
            }
            else if (vy < 0) {
                ang = 270;
            }
            return ang;
        }

        ang = this.getAngle(Math.atan(Math.abs(vy) / Math.abs(vx)));
        if (vx > 0) {
            if (vy < 0) {
                ang = 360 - ang;
            }
        }
        else {
            if (vy > 0) {
                ang = 180 - ang;
            }
            else {
                ang = 180 + ang;
            }
        }
        return ang;
    }
    public static getAngleTwoVec(p1: any, p2: any) {
        let radian = Math.atan2(p2.y, p2.x) - Math.atan2(p1.y, p1.x);
        return this.getAngle(radian);
    }
    /**
     * 获取两点间距离
     * @param {Point} p1
     * @param {Point} p2
     * @returns {number}
     */
    public static getDistance(p1: any, p2: any) {
        let disX = p2.x - p1.x;
        let disY = p2.y - p1.y;
        let disQ = Math.pow(disX, 2) + Math.pow(disY, 2);
        return Math.sqrt(disQ);
    }
    /**
     * 精确到小数点后多少位（舍尾）
     * @param {number} 精确值
     * @param {number} 精确位数
     * @return {number}
     * */
    public static exactCount(exactValue: number, count = 0) {
        let num = Math.pow(10, count);
        let value = (exactValue * num) | 0;
        return value / num;
    }

    /**
     * [0-1]区间获取二次贝塞尔曲线点切线角度
     * @param {Point} p0起点
     * @param {Point} p1控制点
     * @param {Point} p2终点
     * @param {number} t [0-1]区间
     * @return {number}
     * */
    public static getBezierCutAngle(p0: any, p1: any, p2: any, t: number) {
        let _x = 2 * (p0.x * (t - 1) + p1.x * (1 - 2 * t) + p2.x * t);
        let _y = 2 * (p0.y * (t - 1) + p1.y * (1 - 2 * t) + p2.y * t);
        let angle = this.getAngle(Math.atan2(_y, _x));
        return angle;
    }



    public static randomNumBoth(Min: number, Max: number) {
        var Range = Max - Min;
        var Rand = Math.random();
        var num = Min + Math.round(Rand * Range); //四舍五入
        return num;
    }
    //获取连个float之间的随机值
    public static randomFloatBetween(Min: number, Max: number) {
        var Range = Max - Min;
        var Rand = Math.random();
        var num = Min + Rand * Range;
        return num;
    }
    public static probabilityCanHappen(num: number) {
        let random = MathUtils.randomNumBoth(0, 100);
        return random <= num;
    }

    /**
 * 传入概率值数组，返回中标的概率下标
 * @param parr 概率数组
 */
    public static probabilitys(parr: Array<any>) {
        var arr = 0;
        var pres = [...parr];
        var probabilityCount = 0;
        for (let i = 0; i < pres.length; i++) {
            probabilityCount += pres[i];
        }
        if (probabilityCount != 100) {
            throw '所有概率值总和不等于100%';
        }
        var nums = new Array();
        for (let i = 0; i < pres.length; i++) {
            const element = pres[i];
            for (let index = 0; index < element; index++) {
                nums.push(arr);
            }
            arr++;
        }
        var random = this.randomNumBoth(0, 99);
        var targetIndex = nums[random];
        return targetIndex;
    }

    /**
    * @zh 根据旋转轴和旋转弧度计算四元数
    */
    public static fromAxisAngle<Out extends IQuatLike, VecLike extends IVec3Like>(out: Out, axis: VecLike, rad: number) {
        rad = rad * 0.5; // 为什么要除以2？因为公式推导出来的！
        const s = Math.sin(rad);
        out.x = s * axis.x;
        out.y = s * axis.y;
        out.z = s * axis.z;
        out.w = Math.cos(rad);
        return out;
    }

    //数字开头填充0
    static padStart(num: any, n: number) {
        let len = num.toString().length;
        while (len < n) {
            num = "0" + num;
            len++;
        }
        return num;
    }
    //金币转化为100，000  
    static formatMoney = (s: string, type: number) => {
        if (/[^0-9\.]/.test(s))
            return "0.00";
        if (s == null || s == "null" || s == "")
            return "0.00";
        s = s.toString().replace(/^(\d*)$/, "$1.");
        s = (s + "00").replace(/(\d*\.\d\d)\d*/, "$1");
        s = s.replace(".", ",");
        let re = /(\d)(\d{3},)/;
        while (re.test(s))
            s = s.replace(re, "$1,$2");
        s = s.replace(/,(\d\d)$/, ".$1");
        if (type == 0) {
            let a = s.split(".");
            if (a[1] == "00") {
                s = a[0];
            }
        }
        return s;
    };

    //金币转化为 10,000P
    static covertMoney(s: string) {
        let value = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'B', 'aa', 'bb', 'cc', 'dd', 'ee', 'ff', 'gg', 'hh', 'ii', 'jj', 'kk', 'll', 'mm', 'nn', 'oo', 'pp', 'qq', 'rr', 'ss', 'tt', 'uu', 'vv', 'ww', 'xx', 'yy', 'zz'];
        s = this.formatMoney(s, 0);
        let m = (s.match(/,/g) || []).length;
        let n = s.indexOf(','); //-1
        if (m >= 0 && n >= 0) {
            return s.slice(0, n + 4) + value[m - 1];
        } else {
            return s;
        }
    }

    //返回当前到秒的时间戳
    static getTime() {
        return Math.floor(new Date().getTime() / 1000);
    }

    //返回当前天数时间戳  
    static getDay() {
        return Math.floor(Math.floor(new Date().getTime() / 1000) / 86400);
    }

    // 获取当前日期
    static getDate(): string {
        return new Date().toLocaleDateString();
    }

    //返回00：00形式
    static getTimeFormate(t: number) {
        let a = Math.floor(t / 3600);
        let b = Math.floor(t % 3600 / 60);
        let c = Math.floor(t % 60);
        return !!a ? `${this.padStart(a, 2)}:${this.padStart(b, 2)}:${this.padStart(c, 2)}` : `${this.padStart(b, 2)}:${this.padStart(c, 2)}`;
    }

    //h5获取参数
    static getQueryString(name: string) {
        let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
        let r = window.location.search.substr(1).match(reg); //search,查询？后面的参数，并匹配正则
        if (r != null) return unescape(r[2]);
        return null;
    }

    //h5修改参数
    static setQueryString(name: string, replaceName: string) {
        let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
        if (this.getQueryString(name) != null) {
            let url = window.location.href.toString();
            url = url.replace(eval('/(' + name + '=)([^&]*)/gi'), replaceName);
            window.history.replaceState({}, null, url);
            return;
        }
    }

    //显示当前节点树
    static tree(node: any) {
        let style = `color: ${node.parent === null || node.activeInHierarchy ? 'green' : 'grey'};`;
        if (node.children.length > 0) {
            console.groupCollapsed(`%c${node.name}`, style);
            node.children.forEach(child => this.tree(child));
            console.groupEnd();
        } else {
            Debug.log(`%c${node.name}`, style);
        }
    }

    //将RGBA颜色分量转换为一个数值表示的颜色，颜色分量为0~255之间的值
    static convertToNumber(r: number, g: number, b: number, a: number = 255): number {
        return ((r & 0xfe) << 23) | (g << 16) | (b << 8) | a;
    }

    //将十六进制的颜色转换为RGBA分量表示的颜色
    static convertToRGBA(color: number): { r: number, g: number, b: number, a: number } {
        return {
            r: (color & 0xef000000) >> 23,
            g: (color & 0x00ff0000) >> 16,
            b: (color & 0x0000ff00) >> 8,
            a: (color & 0x000000ff),
        };
    }

    //设置同时下载数减少等待时间
    static changeAssetManagerMax() {
        //默认只有6 太少了  只能修改非原生环境
        assetManager.downloader.maxConcurrency = 20;//下载时的最大并发数
        assetManager.downloader.maxRequestsPerFrame = 20;//下载时每帧可以启动的最大请求数
    }

   


}